package com.smarthospital.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.smarthospital.common.Result.CodeMsg;
import com.smarthospital.common.Result.CommonException;
import com.smarthospital.common.util.IDGeneratorUtil;
import com.smarthospital.common.util.SHDateUtil;
import com.smarthospital.common.util.SHWXHttpClient;
import com.smarthospital.contants.SHConst;
import com.smarthospital.dao.daoService.DoctorDaoService;
import com.smarthospital.dao.daoService.InquiryOrderDaoService;
import com.smarthospital.entity.dto.*;
import com.smarthospital.entity.pojo.Doctor;
import com.smarthospital.entity.pojo.InquiryOrder;
import com.smarthospital.entity.pojo.SHOrderRefunds;
import com.smarthospital.entity.pojo.User;
import com.smarthospital.entity.vo.*;
import com.smarthospital.service.PayService;
import com.smarthospital.web.inteceptor.LoginInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * create by sym  2021/5/2 2:06.
 */
@Slf4j
@Service
public class PayServiceImpl implements PayService {
    @Value("${wx.miniApp.notify_url}")
    private String notify_url;
    @Value("${wx.miniApp.refunds_notify_url}")
    private String refunds_notify_url;
    @Value("${wx.miniApp.mchid}")
    private String mchid;

    @Autowired
    private InquiryOrderDaoService inquiryOrderDaoService;
    @Autowired
    private DoctorDaoService doctorDaoService;


    @Override
    public PrePayResultDTO prePayOder(Integer doctorId, Integer payType, Integer inquiryType,String inquiryTime) throws Exception {

        if (Integer.valueOf(2).equals(inquiryType)) {
            SHDateUtil.checkRangeTimePattern(inquiryTime);
        }
        User user = LoginInterceptor.getUser();

        //4、统一下单(下预订单)    _后台生成一条待支付订单 _发起微信支付预订单
        Doctor doctor = doctorDaoService.queryById(Long.valueOf(doctorId));
        InquiryOrder order =  initOrder(user,doctor,inquiryType,inquiryTime,false);
        order.setStatus(1);
        inquiryOrderDaoService.insertSelective(order);
        //todo  具体要哪些信息 需要联调时才确定
        WXPrePayVO dataVo = createPrePayInfo(order);
        //状态码为200时才返回
//        String out = SHWXHttpClient.post(SHConst.WXPay_urls.prePayOrder, dataVo, String.class);
//        WXPayResutlDTO wxPayResutlDTO = JSONObject.parseObject(out, WXPayResutlDTO.class);
//        order.setWxOrderId(wxPayResutlDTO.getPrepay_id());
        //todo
        order.setWxOrderId(IDGeneratorUtil.getWxPayId());
        PrePayOderDTO build = PrePayOderDTO.builder().orderId(order.getId()+"").prepayId(order.getWxOrderId()).build();
        return new PrePayResultDTO(0,build);
    }

    /**
     * @param doctorId
     * @param payType  目前支持微信支付，先不做处理
     * @throws IOException
     */
    public PrePayResultDTO prePayOderBak(Integer doctorId, Integer payType, Integer inquiryType,String inquiryTime) throws Exception {
        if (payType == null) {
            payType =0;
        }
        if (Integer.valueOf(2).equals(inquiryType)) {
            SHDateUtil.checkRangeTimePattern(inquiryTime);
        }
        User user = LoginInterceptor.getUser();
        InquiryOrder orderParam = InquiryOrder.builder().inquiryManId(user.getId()).build();
        List<InquiryOrder> list = inquiryOrderDaoService.queryOrder(orderParam);
        //1、再次下单，需要判断有无待支付订单，必须支付完成才行----->有的话需要将订单返回给前端
        List<InquiryOrder> toPayList = list.stream().filter(o -> o.getStatus().equals(0)).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(toPayList)) {
            return new PrePayResultDTO(1,toPayList);
        }

        //2、下单前判断[该时间段]是否已经有待使用订单 返回该订单
        List<InquiryOrder> nowList = list.stream().filter(o -> o.getStatus().equals(1)).filter(o -> o.getInquiryTime().equals(inquiryTime)).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(nowList)) {
            return new PrePayResultDTO(2,nowList);
        }
        //3、查看是否能白嫖這位醫生
        List<InquiryOrder> list1 = list.stream().filter(o->o.getDoctorId().equals(Long.valueOf(doctorId))).collect(Collectors.toList());
        boolean hasZeroFee = inquiryOrderDaoService.hasZeroFeeMethod(list1);
        //4、统一下单(下预订单)    _后台生成一条待支付订单 _发起微信支付预订单
        Doctor doctor = doctorDaoService.queryById(Long.valueOf(doctorId));
        InquiryOrder order =  initOrder(user,doctor,inquiryType,inquiryTime,hasZeroFee);

        WXPrePayVO dataVo = createPrePayInfo(order);
        //状态码为200时才返回
        String out = SHWXHttpClient. post(SHConst.WXPay_urls.prePayOrder,dataVo, String.class);
        WXPayResutlDTO wxPayResutlDTO = JSONObject.parseObject(out, WXPayResutlDTO.class);
        order.setWxOrderId(wxPayResutlDTO.getPrepay_id());
        inquiryOrderDaoService.insertSelective(order);
        //todo  具体要哪些信息 需要联调时才确定
        PrePayOderDTO build = PrePayOderDTO.builder().prepayId(wxPayResutlDTO.getPrepay_id()).build();
        return new PrePayResultDTO(0,build);
    }


    /**
     * 生成订单
     * 音视频类型直接创建房间号
     */
    private InquiryOrder initOrder(User user, Doctor doctor, Integer inquiryType,String inquiryTime,boolean hasZeroFee) {
        InquiryOrder order = new InquiryOrder();
        order.setStatus(0);
        order.setCreateTime(new Date());
        order.setMajor(doctor.getMajor());
        //写死 后续每个医生不一样，应该配置在医生信息上
        order.setLeftVedioTime(20);
        if (hasZeroFee) {
            order.setTotal(0);
        }else {
            double total = inquiryType == 0 ? doctor.getImageTextPrice() : inquiryType == 1 ? doctor.getPhonePrice() : doctor.getVideoPrice();
            int totalCoins = (int)(total*100);
            order.setTotal(totalCoins);
        }

        order.setDoctor(doctor.getName());
        order.setDoctorKey(doctor.getDoctor());
        order.setDoctorId(doctor.getId());
        order.setDoctorLevel(doctor.getDoctorLevel());

        order.setInquiryMan(!StringUtils.isEmpty(user.getIdCardName()) ? user.getIdCardName():user.getNickName());
        order.setInquiryManId(user.getId());
        order.setInquiryTime(inquiryTime); //排班时间 需要前端传 check?
        order.setInquiryType(inquiryType);
        order.setHospital(doctor.getHospital()); //医生的医院
        if ( inquiryType == 2||inquiryType == 1) {
            order.setRoomId(IDGeneratorUtil.generateTRTCRoomId());
        }

        return order;
    }







    //生成预订单
    private WXPrePayVO createPrePayInfo(InquiryOrder order) {
        User user = LoginInterceptor.getUser();
        return WXPrePayVO.builder()
                .description("智慧医院在线"+(order.getInquiryType()==1?"视频":"图文")+ ( order.getDoctorLevel() == 0? "问诊":"专家问诊")+"订单")
                .out_trade_no(order.getId()+"") //就用数据库id
                .amount(new WXAmountVO(order.getTotal() ,"CNY"))
                .time_expire(new Date())
                .notify_url(notify_url)
                .payer(new WXPayerVO(user.getOppenId()))
                .build();
    }

    /**
     * 微信支付回调
     * @param request
     * @param parm
     */
    @Override
    public void payCallBack(HttpServletRequest request, JSONObject parm) {
        /**
         *
         * 1.解密参数
         * 2.校验appid  mchid
         * 3.校验oppenId  out_trade_no
         * 4.修改订单状态
         */
    }

    /**
     * 取消订单按钮---->发起微信订单取消  ----> 将本地订单状态改为已经取消，
     *
     * 微信取消前需要先查询，如果已经支付，须告知用户
     * 1.查询用户的此订单
     * 2.核对订单状态
     * 3.修改订单状态
     * 4.调用微信服务关闭订单
     * @param orderId
     */
    @Override
    public void closeOrder(String orderId) throws IOException {
        User user =LoginInterceptor.getUser();
        //1.查询用户的此订单
        InquiryOrder param = InquiryOrder.builder().inquiryManId(user.getId()).id(Long.valueOf(orderId)).build();
        List<InquiryOrder> list = inquiryOrderDaoService.queryOrder(param);
        if (list.size() == 0) {
            throw new CommonException(CodeMsg.ERROR_NO_ORDER);
        }
        if (list.size() > 1) {
            throw new CommonException(CodeMsg.ERROR_DATA);
        }
        InquiryOrder order = list.get(0);
        //2.核对订单状态
        if (0 != order.getStatus()) {
            throw new CommonException(CodeMsg.ERROR_ORDER_OVER);
        }
        //3.修改订单状态  单独写个方法的目的是后续可追宗 会加记录
        inquiryOrderDaoService.closeOrder(orderId);
        //4.调用微信服务关闭订单
        String url = String.format(SHConst.WXPay_urls.closeOrder,orderId);
        WXCloseOrderVO build = WXCloseOrderVO.builder().mchid(mchid).out_trade_no(orderId).build();

    }


    @Override
    public WXQueryOderDTO queryOrder(String orderId) throws Exception {
        String url = String.format(SHConst.WXPay_urls.queryOrder,orderId,mchid);
        String out = SHWXHttpClient.get(url,String.class);
        return JSONObject.parseObject(out,WXQueryOderDTO.class);
    }

    /**
     * 发起退款
     * 应该要记录流水 todo
     * 订单时否处于支付完成状态
     * 发起微信退款
     * 修改订单状态
     * @return
     */
    @Override
    public RefundsDTO refunds(String orderId,String reason) throws Exception {
        InquiryOrder order = inquiryOrderDaoService.queryById(Long.valueOf(orderId));
        if (!Integer.valueOf(1).equals(order.getStatus())) {
            throw new CommonException(CodeMsg.ERROR_ORDER_STATUS);
        }
        //退款id
        String refundsId = IDGeneratorUtil.generateRefundsId();
        WXRefundsAmountVO amount = WXRefundsAmountVO.builder().currency("CNY").refund(order.getTotal()).total(order.getTotal()).build();
        RefundsVO param = RefundsVO.builder()
                .out_trade_no(orderId)
                .out_refund_no(refundsId)
                .notify_url(refunds_notify_url)
                .reason(reason)
                .amount(amount)
                .build();
        String out = SHWXHttpClient.post( SHConst.WXPay_urls.refunds,param,String.class);
        RefundsDTO refundsDTO = JSONObject.parseObject(out,RefundsDTO.class);

        if ("SUCCESS".equals(refundsDTO.getStatus())) {
            order.setStatus(4);
            inquiryOrderDaoService.update(order);
            //插入流水 todo
            SHOrderRefunds shOrderRefunds = SHOrderRefunds.builder().build();
        }
        return refundsDTO;
    }


}
